{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Image Processing with Convolutions\n",
    "\n",
    "In image processing, most image filters and image transformation use convolutions. Convolutions modify the original matrix of pixels through a pointwise multiplication with a kernel or filter matrix. Wikipedia describes <a href=\"https://en.wikipedia.org/wiki/Kernel_(image_processing)\">convolutions on images</a> as:\n",
    "\n",
    "> Convolution is the process of multiplying each element of the image with its local neighbors, weighted by the kernel. For example, if we have two three-by-three matrices, one a kernel, and the other an image piece, convolution is the process of flipping both the rows and columns of the kernel and then multiplying locationally similar entries and summing. The [2,2] element of the resulting image would be a weighted combination of all the entries of the image matrix, with weights given by the kernel: \n",
    "\n",
    "> ![Image of convolution](https://wikimedia.org/api/rest_v1/media/math/render/svg/1a5bdd585d515770c888ea5b4ea07a7a5166cc8d)\n",
    "\n",
    "Amongst the suite of applications of convolutions, image blurring and sharpening as well as edge detection are the most common. In this demo, we will use MLDB query to efficiently transform images. To do so, we will use the [MNIST database of handwriten digits](http://yann.lecun.com/exdb/mnist/).\n",
    "\n",
    "In this demo, we will use the [jseval](../../../../doc/#builtin/sql/ValueExpression.md.html#jseval) function to execute JavaScript code inline with SQL, and the [SQL Expression Function](../../../../doc/#builtin/functions/SqlExpressionFunction.md.html) to persist and reuse the same JavaScript code."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "The notebook cells below use `pymldb`'s `Connection` class to make [REST API](../../../../doc/#builtin/WorkingWithRest.md.html) calls. You can check out the [Using `pymldb` Tutorial](../../../../doc/nblink.html#_tutorials/Using pymldb Tutorial) for more details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from pymldb import Connection\n",
    "mldb = Connection()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "... And other Python librairies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "import numpy as np\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "from IPython.display import display, Latex\n",
    "from ipywidgets import widgets, interact"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading the data\n",
    "\n",
    "A pickled version of the dataset is available on the [deeplearning.net website](http://deeplearning.net/tutorial/gettingstarted.html).\n",
    "\n",
    "The dataset has been unpickled and saved in a public Amazon's S3 cloud storage. Check out MLDB's [Protocol Handlers](../../../../doc/#builtin/Url.md.html) for Files and URLS for more details on loading remote ressources."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Response [201]>\n"
     ]
    }
   ],
   "source": [
    "data_url_mnist = 'http://public.mldb.ai/datasets/digits_data.csv.gz'\n",
    "\n",
    "print mldb.put('/v1/procedures/import_digits_mnist', {\n",
    "    \"type\":\"import.text\",\n",
    "    \"params\": {\n",
    "        \"dataFileUrl\": data_url_mnist,\n",
    "        \"outputDataset\": \"digits_mnist\",\n",
    "        \"select\": \"{* EXCLUDING(\\\"785\\\")} AS *, \\\"785\\\" AS label\",\n",
    "        \"runOnCreation\": True,\n",
    "    }\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Taking a random image and starting image manipulation\n",
    "\n",
    "Similarly to the first few steps in the [Real-Time Digits Recognizer](../../../../doc/nblink.html#_demos/Real-Time%20Digits%20Recognizer.ipynb) demo, we will display random MNIST digits from the test set. At each refresh, we get a randomly selected row using the [`sample` function in a SQL From Expression](../../../../doc/#builtin/sql/FromExpression.md.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\ngg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fc50371e9d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "data = mldb.query(\"\"\"\n",
    "    SELECT * EXCLUDING(label) \n",
    "    FROM sample(\n",
    "                (select * from digits_mnist where rowHash() % 5 = 0),\n",
    "                {rows: 1}\n",
    "    )\n",
    "\"\"\")\n",
    "\n",
    "image = data.as_matrix().reshape(28, 28)\n",
    "plt.imshow(image)\n",
    "plt.gray()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining the convolution function\n",
    "\n",
    "A discrete convolution can be defined mathematically as:\n",
    "\n",
    "$newPixel[i,j] = \\sum_{y=i}^{i+r}\\sum_{x=j}^{j+r}oldPixel[x,y] \\cdot weight[x,y]$\n",
    "\n",
    "where the $weight[]$ matrix (see 'kernelDict' dictionary in a couple of cells below) defines the type of image manipulation and $r$ is the area of effect. Imagine a \"square box\" centered at the pixel that you want to transform. The kernel weighted sum of \"old pixels\" in the \"square box\" gives you a \"new pixel\".\n",
    "\n",
    "As seen in the code below, each new pixel in the convolved picture is the weighted sum of the the pixel and its neighboring pixels where the weights are the values in the kernel matrix.  \n",
    "\n",
    "Doing convolutions with custom function of type [SQL Expression Function](../../../../doc/#builtin/functions/SqlExpressionFunction.md.html) and [jseval](../../../../doc/#builtin/sql/ValueExpression.md.html) for inline definition of functions using Javascript allows us to process large amounts of data using the optimizations inherent to MLDB. Convolutions are typically very time consuming operations with \n",
    "$O(n\\cdot r^2)$ complexity in this case where n is the number of features and r is the radius (i.e. neighboring pixels).\n",
    "\n",
    "There were two steps to creating the function below:\n",
    "* JsConvolutionExpr used a jseval built-in function where all the logic resides\n",
    "* A 'convolution' SQL Expression Function is created, allowing us to call 'convolution' with a simple [mldb.query](../../../../doc/#builtin/sql/Sql.md.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Response [201]>\n"
     ]
    }
   ],
   "source": [
    "# JavaScript code loosely based on Ivan Kuckir's blog post: http://blog.ivank.net/fastest-gaussian-blur.html\n",
    "\n",
    "def create_convolution():\n",
    "    \n",
    "    JsConvolutionExpr = \"\"\"\n",
    "        jseval('\n",
    "            var row_val = val;\n",
    "            var dim = Math.sqrt(row_val.length);\n",
    "            var radius = Math.sqrt(kernel.length);\n",
    "            \n",
    "            \n",
    "            /*************************************\n",
    "            ******** Function Definition *********\n",
    "            **************************************/\n",
    "\n",
    "            // input 1D list, output 1D list, pixel matrix dimensions\n",
    "            function convolution(inList, outList, width, height, radius) {\n",
    "\n",
    "                for (var i = 0; i < height; i++)\n",
    "                    for (var j = 0; j < width; j++) {\n",
    "                        var newPixel = 0;\n",
    "                        var indexW = 0;\n",
    "                        \n",
    "                        for (var yr = i; yr < i + radius; yr++)\n",
    "                            for (var xr = j; xr < j + radius; xr++) {\n",
    "                            \n",
    "                              var y = Math.min(height - 1, Math.max(0, yr));\n",
    "                              var x = Math.min(width - 1, Math.max(0, xr));\n",
    "                              \n",
    "                              newPixel = newPixel + inList[y * width + x] * weights[indexW];\n",
    "                              indexW ++;\n",
    "                            }\n",
    "                            \n",
    "                        new_value = newPixel;\n",
    "                        outList[i * width + j] = new_value;\n",
    "                    }\n",
    "                return outList;\n",
    "            } // End of convolution\n",
    "            \n",
    "            //Assuring that the 1d row is in the right order\n",
    "            function arrangeMatrix(inList) {\n",
    "            \n",
    "                var length = inList.length;\n",
    "                var data = new Array(length);\n",
    "                for (var i = 0; i < length; i++) {\n",
    "                    data[parseInt(inList[i][0][0])] = inList[i][1];\n",
    "                }\n",
    "                return data\n",
    "            }\n",
    "            \n",
    "            /*************************************\n",
    "            ********** Using Functions ***********\n",
    "            **************************************/\n",
    "            \n",
    "            var weights = arrangeMatrix(kernel); // filter matrix\n",
    "            var matrix = arrangeMatrix(row_val); // my picture\n",
    "            var convolvedMatrix = [];\n",
    "            \n",
    "            convolution(matrix, convolvedMatrix, dim, dim, radius);\n",
    "\n",
    "            return convolvedMatrix;',\n",
    "            'val, kernel', \n",
    "             valueExpr, kernel\n",
    "        ) AS *\n",
    "    \"\"\"\n",
    "\n",
    "\n",
    "    print mldb.put(\"/v1/functions/convolution\", {\n",
    "        \"type\": \"sql.expression\",\n",
    "        \"params\": {\n",
    "            \"expression\": JsConvolutionExpr,\n",
    "            \"prepared\": True\n",
    "        }\n",
    "    })\n",
    "    \n",
    "create_convolution()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function will used in the interactive menu in the next section. We will take the image of the digit that we have seen before and apply different filters. You will need to load the cells in this notebook to make it work."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using the convolution function\n",
    "\n",
    "We will first define the type filters or kernels that we want to try."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "kernelDict = {\n",
    "    'Right Sobel': [-1, 0, 1, -2, 0, 2, -1, 0, 1], \n",
    "    'Detect Edges': [1, 1, 1, 1, -8, 1, 1, 1, 1],\n",
    "    'Sharpen': [0, -1, 0, -1, 5, -1, 0, -1, 0],\n",
    "    'Box Blur': [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],\n",
    "    'Approximated Gaussian Blur': [0.0625, 0.125, 0.0625, 0.125, 0.25, 0.125, 0.0625, 0.125, 0.0625]\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def convolutionFunc(image_processing):\n",
    "    \n",
    "    SQL_Expr = \"\"\"\n",
    "        SELECT convolution({\n",
    "                valueExpr: %(data)s,\n",
    "                kernel: %(kernel)s\n",
    "        }) AS *\n",
    "    \"\"\" %   {\n",
    "                \"data\": data.values[0].tolist(),\n",
    "                \"kernel\": kernelDict[image_processing]\n",
    "            }\n",
    "\n",
    "    convolvedData = mldb.query(SQL_Expr)\n",
    "    image = convolvedData.as_matrix().reshape(28, 28)\n",
    "    plt.imshow(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Choose an image processing option from the drop-down menu\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fc5011b5910>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "options=('Right Sobel', 'Detect Edges', 'Sharpen', 'Box Blur', 'Approximated Gaussian Blur')\n",
    "interact(convolutionFunc, image_processing=kernelDict.keys(), );\n",
    "print \"Choose an image processing option from the drop-down menu\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I found the 'Detect Edges' convolution particularly useful when training image recognition models. This can be useful in many Machine Vision applications."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Convolutions with MLDB's TensorFlow plug-in\n",
    "\n",
    "Not everyone will want to code their own convolutions from scratch (such as with the `create_convolution()` function above). In fact, given the myriad of tools available, it may save you time and effort to use external librairies. MLDB has integrated the TensorFlow Open Source Library for Machine Intelligence allowing us to leverage some of the great Computer Vision APIs and GPU accelaration that it offers. Let's get started with the same images as before.\n",
    "\n",
    "First, I reshape my image and kernel lists into 4D tensors in the NHWC tensor format. Then, I use the [`tf_Conv2D`](../../../../doc/builtin/sql/ValueExpression.md.html#builtinfunctions), the TensorFlow operator that is exposed as an MLDB built-in function directly in SQL."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "data_ = data.values[0].reshape(1, 28, 28, 1).tolist() \n",
    "# image input must be a [batch, in_height, in_width, in_channels] shaped tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def TensorFlowConvolution(image_processing):\n",
    "    \n",
    "    kernel = np.asarray(kernelDict[image_processing]).reshape(3, 3, 1, 1).tolist() \n",
    "    # kernel must be a [filter_height, filter_width, in_channels, out_channels] shaped tensor\n",
    "    strides = [ 1, 1, 1, 1]\n",
    "    SQL_Expr = \"\"\"\n",
    "        SELECT tf_Conv2D(\n",
    "            {input: %(data)s, filter: %(kernel)s}, \n",
    "            {T: { type: 'DT_FLOAT'}, padding: 'SAME', strides: %(strides)s })\n",
    "        AS *\n",
    "    \"\"\" %   {\n",
    "                \"data\": data_,\n",
    "                \"kernel\": kernel,\n",
    "                \"strides\": strides\n",
    "            }\n",
    "    \n",
    "    convolvedData = mldb.query(SQL_Expr)\n",
    "    image = convolvedData.as_matrix().reshape(28, 28)\n",
    "    plt.imshow(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Choose an image processing option from the drop-down menu\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fc50323a950>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "options=('Right Sobel', 'Detect Edges', 'Sharpen', 'Box Blur', 'Approximated Gaussian Blur')\n",
    "interact(TensorFlowConvolution, image_processing=kernelDict.keys(), );\n",
    "print \"Choose an image processing option from the drop-down menu\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here are a few definitions:\n",
    "* Batch: The data is sometimes split into batches to parallelize Image Processing.\n",
    "* Strides: Stride is a step that the \"square box\" (as described in 'Defining the Convolution Function' section above) will take. A stride has shape [stride_batch, stride_width, stride_height, stride_channel] so [1, 1, 1, 1] will shift the box one pixel at the time for each batch and each channel.\n",
    "* Padding: As you may have noticed, sometimes the \"square box\" has elements outside the picture (i.e. for pixels at the boundries of the image). The 'SAME' padding allows the convolution algorithm to go beyond picture borders. Pixels in the padding area will typically be zero and the output image will have the same size as the input image. 'VALID' padding does not allow the \"square box\" to go beyond the picture boundries. In this case, the output picture size will be smaller. For moreinformation, see [this article](http://radio.feld.cvut.cz/matlab/toolbox/images/linfilt4.html).\n",
    "* Channel: we have only one channel here because it is grayscale. For images with colors (i.e. RGB), we have 3 channels. See ImageMagick's [Color Basics and Channels](http://www.imagemagick.org/Usage/color_basics/) article for more information."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Where to next?\n",
    "\n",
    "Now you can move on to the [Real-Time Digits Recognizer](../../../../doc/nblink.html#_demos/Real-Time Digits Recognizer) demo where we'll show the machine learning steps to follow to build *MLPaint*, the real-time digits recognizer plugin.\n",
    "\n",
    "Otherwise, check out the other [Tutorials and Demos](../../../../doc/#builtin/Demos.md.html)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
